package com.kdg.javaEight;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.StampedLock;
import java.util.stream.IntStream;

/**
 * Created by kong on 2017/9/1.
 */
public class TestJuc {

    static Lock lock = new ReentrantLock();

    /*线程和执行器*/
    public static void test(String[] args) {

        ExecutorService executorService = Executors.newCachedThreadPool();
        /*executorService.submit(() -> {
            String name = Thread.currentThread().getName();
            System.out.println("Hello "+name);
            System.out.println("attempt to shutdown executor");
            executorService.shutdown();
            try {
                executorService.awaitTermination(5, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                System.err.println("task interrupted");
            }finally {
                if(!executorService.isShutdown()){
                    System.err.println("cancel non-finished tasks");
                }
                executorService.shutdownNow();
                System.out.println("shutdown finished");
            }
        });*/
        /*Callable<Integer> task = () -> {
            try {
                TimeUnit.SECONDS.sleep(1);
                return 123;
            }
            catch (InterruptedException e) {
                throw new IllegalStateException("task interrupted", e);
            }
        };

        Future<Integer> result = executorService.submit(task);
        System.out.println("future done?" + result.isDone());
        try {
            Integer integer = result.get(2,TimeUnit.SECONDS);
            System.out.println("future done? " + result.isDone());
            System.out.print("result: " + integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }*/

        /*Callable<String> cal1 = () -> "task1";
        Callable<String> cal2 = () -> "task2";
        Callable<String> cal3 = () -> "task3";
        Callable<String> cal4 = () -> "task4";

        List<Callable<String>> lst = new ArrayList<Callable<String>>();
        lst.add(cal1);lst.add(cal2);lst.add(cal3);lst.add(cal4);

        try {
            executorService.invokeAll(lst)
                    .stream()
                    .map(future -> {
                        try {
                            return future.get();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        }
                        return null;
                    })
                    .forEach(System.out::println);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        Callable<String> cal1 = () -> {
            TimeUnit.SECONDS.sleep(3);
            return "task1";
        };
        Callable<String> cal2 = () -> {
            TimeUnit.SECONDS.sleep(2);
            return "task2";
        };
        Callable<String> cal3 = () -> {
            TimeUnit.SECONDS.sleep(1);
            return "task3";
        };
        Callable<String> cal4 = () -> {
            TimeUnit.SECONDS.sleep(5);
            return "task4";
        };

        List<Callable<String>> lst = new ArrayList<Callable<String>>();
        lst.add(cal1);lst.add(cal2);lst.add(cal3);lst.add(cal4);

        ExecutorService executor = Executors.newWorkStealingPool();
        try {
            String result = executor.invokeAny(lst);//通过invokeAny()将这些callable提交给一个executor，返回最快的callable的字符串结果
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    /*同步和锁*/
    public static void main(String[] args) {
//        test();
//        testWRLock();
        testStampLock();
    }

    /**
     * 读写锁
     */
    private static void testWRLock() {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Map hashMap = new HashMap();
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

        executorService.submit(() -> {  //写锁
            lock.writeLock().lock();
            try {
                sleep(2);
                hashMap.put("kkk",123);
            } finally {
                lock.writeLock().unlock();
            }
        });
        Runnable task = () -> {
            lock.readLock().lock();
            try {
                System.out.println(hashMap.get("kkk"));
                sleep(1 );
            } finally {
                lock.readLock().unlock();
            }
        };

        executorService.submit(task);
        executorService.submit(task);  //读锁可以安全同步获取，只要是没有其他线程获取了写锁

        stop(executorService);

    }

    /**
     * synchrosize   lock
     */
    static void test(){
        ExecutorService executor = Executors.newFixedThreadPool(2);

        IntStream.range(0,100000)
                .forEach(i -> executor.submit(TestJuc::increment));

        stop(executor);
        System.out.println(count);
    }

    /**
     * stampLock --支持读写锁  返回表示为long的标记
     */
    private static void testStampLock(){
        //支持乐观锁
        ExecutorService executor = Executors.newFixedThreadPool(2);
        StampedLock stampedLock = new StampedLock();

        //乐观锁的获取方式tryOptimisticRead()   它的意思是在乐观读锁的过程中不会阻止其他线程获取写锁，当有其他线程获取写锁后，该乐观锁失效
        /*executor.submit(() -> {
            long stamp = stampedLock.tryOptimisticRead();
            try {
                System.out.println("Optimistic Lock valid:"+stampedLock.validate(stamp));
                sleep(1);
                System.out.println("Optimistic Lock valid:"+stampedLock.validate(stamp));
                sleep(2);
                System.out.println("Optimistic Lock valid:"+stampedLock.validate(stamp));
                sleep(3);
            } finally {
                stampedLock.unlock(stamp);
            }
        });

        executor.submit(() -> {
            long l = stampedLock.writeLock();

            try {
                System.out.println("write lock acquired");
                sleep(2);
            } finally {
                stampedLock.unlock(l);
                System.out.println("Write down");
            }
        });*/


        executor.submit(() -> {
            long readL = stampedLock.readLock();
            try {
                if(count == 0){
                    readL = stampedLock.tryConvertToWriteLock(readL);  //能会返回为零的标记，表示当前没有可用的写锁
                    if(readL == 0L){  //此处就是判断如果没有可用的写锁那就调用写锁阻塞当前线程，知道有可用的写锁
                        System.out.println("Couldn't convert to write lock");
                        stampedLock.writeLock();
                    }
                    count = 33;
                }
                System.out.println(count);
            } finally {
                stampedLock.unlock(readL);
            }
        });
        stop(executor);
    }

    static int count = 0;
    static synchronized void incrementSync(){
        count += 1;
    }

    static void increment(){
        lock.lock();
        count += 1;
        lock.unlock();
    }



    public static void stop(ExecutorService executor) {
        try {
            executor.shutdown();
            executor.awaitTermination(60, TimeUnit.SECONDS);
        }
        catch (InterruptedException e) {
            System.err.println("termination interrupted");
        }
        finally {
            if (!executor.isTerminated()) {
                System.err.println("killing non-finished tasks");
            }
            executor.shutdownNow();
        }
    }

    public static void sleep(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }

}
